using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace FW
{
    public class DeepCompare
    {
        // 深度遍历比较两个对象，支持对象里面有List<>, Dictionary<> , class, strut, enum 等类型
        public static bool Compare(object value1, object value2)
        {
            if (value1 == null && value2 == null)
            {
                return true;
            }
            if (value1 == null || value2 == null)
            {
                return false;
            }
            if (value1.GetType() != value2.GetType())
            {
                return false;
            }

            if(value1.GetType().IsPrimitive && value2.GetType().IsPrimitive){ // int float bool
                return value1.Equals(value2);
            } 
            else if(value1.GetType().IsEnum && value2.GetType().IsEnum){ // enum
                return value1.Equals(value2);
            } 
            else if(value1.GetType() == typeof(string) && value2.GetType() == typeof(string)){ // string
                return value1.Equals(value2);
            } 
            else if (value1 is IEnumerable && value2 is IEnumerable) // 注意 string 也会走这里，故把string 放前面
            {
                var enumerable1 = value1 as IEnumerable;
                var enumerable2 = value2 as IEnumerable;

                var enumerator1 = enumerable1.GetEnumerator();
                var enumerator2 = enumerable2.GetEnumerator();

                bool eMove1 = enumerator1.MoveNext();
                bool eMove2 = enumerator2.MoveNext();
                while (eMove1 && eMove2)
                {
                    if (!Compare(enumerator1.Current, enumerator2.Current))
                    {
                        return false;
                    }
                    eMove1 = enumerator1.MoveNext();
                    eMove2 = enumerator2.MoveNext();
                }

                if (eMove1 || eMove2)
                {
                    return false;
                }

                return true;
            }
            else if (value1 is IDictionary && value2 is IDictionary)
            {
                var dict1 = value1 as IDictionary;
                var dict2 = value2 as IDictionary;

                if (dict1.Count != dict2.Count || !dict1.Keys.Cast<object>().All(key => dict2.Contains(key) && Compare(dict1[key], dict2[key])))
                {
                    return false;
                }

                return true;
            } 
            else if(value1.GetType().IsValueType && !value1.GetType().IsPrimitive)   // struct
            {
                return DeepCompareClass(value1, value2);    // 如果是struct，没有 class, List, Dictionary, 直接可以用 value1.Equals(value2)比较      
            }    
            else if(value1.GetType().IsClass && value2.GetType().IsClass)   // class
            {
                return DeepCompareClass(value1, value2);
            }

            return value1.Equals(value2);
        }

        public static bool DeepCompareClass(object obj1, object obj2)
        {
            var properties = obj1.GetType().GetProperties();
            foreach (var property in properties)
            {
                var value1 = property.GetValue(obj1);
                var value2 = property.GetValue(obj2);

                if (!Compare(value1, value2))
                {
                    return false;
                }
            }

            var fields = obj1.GetType().GetFields();
            foreach (var field in fields)
            {
                var value1 = field.GetValue(obj1);
                var value2 = field.GetValue(obj2);
                if (!Compare(value1, value2))
                {
                    return false;
                }
            }
            return true;
        }
    }    
}


